using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.IO;

namespace DejaVuTocReader
{
    
        /**
     * This class decodes outline (bookmarks) contained within a chunk and
     * represents them in a tree structure.
     *
     * @author $author$
     * @version $Revision: 1.8 $
     */
    public class Bookmark
    {
      //~ Instance fields --------------------------------------------------------

      // DjVmDir object
      private DjVmDir djvmDir = null;

      // Object: If String relative or blank url.  If Number, page number.
      private Object obj = null;

      // example:  "Section 3.5 - Encryption"
      private String  displayName             = null;
      
      // The childen for this bookmark
      private ArrayList children              = new ArrayList();
      
      // True if the URL should be used as the display name.
      private bool urlAsDefaultDisplayName = false;

      // indicates if this bookmark is valid
      private bool valid = true;

      //~ Methods ----------------------------------------------------------------

      /**
       * Query if this is image data.
       *
       * @return false
       */
      public bool isImageData()
      { 
          return false;
      }

      /**
       * Query the Vector of children bookmarks.
       *
       * @return the Vector of children
       */
      public ArrayList getChildren()
      {
        return children;
      }

      /**
       * Set the display name for this bookmark.
       *
       * @param displayName the name to be displayed for this bookmark
       */
      public void setDisplayName(String displayName)
      {
        this.displayName = displayName;
      }

      /**
       * Query the display name.
       *
       * @return the display name for this bookmark
       */
      public String getDisplayName()
      {
        String retval = displayName;

        if((retval == null) && urlAsDefaultDisplayName)
        {
          DjVmDir djvmDir = getDjVmDir();

          if(djvmDir != null)
          {
            Object url = djvmDir.getInitURL();

            if(url != null)
            {
              retval = url.ToString();

              int i = retval.LastIndexOf('/');

              if(i >= 0)
              {
                retval = retval.Substring(i + 1);
              }
            }
          }
        }

        return retval;
      }

      /**
       * Set the document directory.
       *
       * @param djvmDir the document directory
       */
      public void setDjVmDir(DjVmDir djvmDir)
      {
        if(djvmDir != null)
        {
          if(size() == 0)
          {
            urlAsDefaultDisplayName = true;

            int          pageno     = 0;
            ArrayList files_list = djvmDir.get_files_list();

            for(IEnumerator e = files_list.GetEnumerator(); e.MoveNext();)
            {
              Bookmark bookmark = new Bookmark();
              DjVmDir.File   file = (DjVmDir.File)e.Current;

              if(file.is_page())
              {
                bookmark.setDisplayName(file.get_title());
                bookmark.setObject(pageno++);
                addElement(bookmark);
              }
            }
          }
        }

        setDjVmDir(
          djvmDir,
          elements());
      }

      /**
       * Query the document directory.
       *
       * @return the document directory.
       */
      public DjVmDir getDjVmDir()
      {
        return djvmDir;
      }

     

      /**
       * Associate an obj with this bookmark.
       *
       * @param obj associated obj
       */
      public void setObject(Object obj)
      {
        this.obj = obj;
      }

      /**
       * Query the obj associated with this bookmark.
       *
       * @return the obj associated with this bookmark
       */
      public Object getObject()
      {
        return obj;
      }

      /**
       * Query the page number linked to this bookmark.
       *
       * @return the page number linked to this bookmark
       */
      public int getPageno()
      {
        Object obj = getObject();

        if(obj is int)
        {
          return (int)obj;
        }

        if(!(obj is String))
        {
          return -1;
        }

        DjVmDir djvmDir = getDjVmDir();

        if(djvmDir == null)
        {
          return -1;
        }

        int retval = djvmDir.getPageno((String)obj);

        if(retval >= 0)
        {
          setObject(retval);
        }

        return retval;
      }

      /**
       * Add a child bookmark.
       *
       * @param child bookmark to add
       */
      public void addElement(Bookmark child)
      {
        getChildren().Add(child);
      }

      

      /**
       * Sets the size of this vector.
       *
       * @param size DOCUMENT ME!
       */
      public void setSize(int size)
      {
        setValid(false);
        if (size > getChildren().Count)
            getChildren().Capacity = size;
        else
        {
            for (int i = getChildren().Count - 1; i >= size; i--)
            {
                getChildren().RemoveAt(i);
            }
            getChildren().Capacity = size;
        }
        setValid(true);
      }

      /**
       * Set whether a bookmark is considered valid.
       *
       * @param valid true if valid
       */
      public void setValid(bool valid)
      {
        this.valid = valid;
      }

      /**
       * Check if a bookmark is valid.
       *
       * @return true if valid
       */
      public bool isValid()
      {
        return valid;
      }

      /**
       * Decodes the directory from the specified datapool.
       *
       * @param input - the BSInputStream to read from.
       */
      public void decode(CachedInputStream input)
      {
        setSize(0);
        setObject(null);
        setDisplayName(null);
        setValid(false);

        try
        {
          for(int count = input.read16(); count > 0;)
          {
            count -= readElement(input);
          }

          flatten();
          setValid(true);
        }
        catch(Exception exp)
        {
          throw exp;
        }
      }

      /**
       * Query a child bookmark.
       *
       * @param item child number
       *
       * @return the child bookmark
       */
      public Bookmark elementAt(int item)
      {
        return (Bookmark)getChildren()[item];
      }

      /**
       * Query the Enumeration of childen.
       *
       * @return the Enumeration of childen
       */
      public IEnumerator elements()
      {
        return getChildren().GetEnumerator();
      }

      /**
       * Query the number of children.
       *
       * @return the number of children
       */
      public int size()
      {
        return getChildren().Count;
      }

      /**
       * Recursively move childrens children as children.
       */
      protected void flatten()
      {
        for(IEnumerator e = elements(); e.MoveNext();)
        {
          ((Bookmark)e.Current).flatten();
        }

        while(size() == 1)
        {
          String   displayName = getDisplayName();
          Bookmark child = elementAt(0);

          if(displayName == null)
          {
            setDisplayName(child.getDisplayName());
            setObject(child.getObject());
          }
          else if(child.getDisplayName() != null)
          {
            break;
          }

          setSize(0);

          for(IEnumerator e = child.elements(); e.MoveNext();)
          {
            addElement((Bookmark)e.Current);
          }
        }
      }

      // Set the document directory and all the bookmarks with an Enumeration.
      private void setDjVmDir(
        DjVmDir     djvmDir,
        IEnumerator e)
      {
        this.djvmDir = djvmDir;

        while(e.MoveNext())
        {
          Bookmark bookmark = (Bookmark)e.Current;
          bookmark.setDjVmDir(
            djvmDir,
            bookmark.elements());
        }
      }

      // read in a bookmark and all of its children.
      private int readElement(CachedInputStream input)
      {
        Bookmark bookmark = new Bookmark();
        int      count = input.read();

        if(count < 0)
        {
          throw new IOException("Unexpected EOF");
        }

        int textsize = input.read24();

        if(textsize < 0)
        {
          throw new IOException("Unexpected EOF");
        }

        if(textsize > 0)
        {
          bookmark.setDisplayName(input.readSizedUTF(textsize));
        }

        textsize = input.read24();

        if(textsize < 0)
        {
          throw new IOException("Unexpected EOF");
        }

        if(textsize > 0)
        {
          bookmark.setObject(input.readSizedUTF(textsize));
        }

        int retval = 1;

        try
        {
          if(count > 0)
          {
            bookmark.setValid(false);

            for(int i = 0; i < count; i++)
            {
              retval += bookmark.readElement(input);
            }

            bookmark.setValid(true);
          }
        }
        finally
        {
          addElement(bookmark);
        }

        return retval;
      }
    }



}
